package eu.telecombretagne.rsm.base.event.manager;

import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;

import eu.telecombretagne.rsm.base.entity.Entity;
import eu.telecombretagne.rsm.base.event.Event;
import eu.telecombretagne.rsm.base.event.EventChannel;
import eu.telecombretagne.rsm.gui.NameConsts;
import eu.telecombretagne.rsm.gui.frames.DesktopFrame;

public class EventService {
	
	/**
	 * Dispatches a given event to an event channel.
	 * 
	 * @param pEvent An event to be dispatched.
	 * @param pEventChannel An event channel.
	 * @param pProducerClass A current event producer.
	 */
	public static void produceEvent(Event pEvent, EventChannel pEventChannel, Class<? extends Entity> pProducerClass){
		ArrayList<Event> eventList = createEventList(pEvent, pProducerClass);
		dispatchEvent(eventList, pEventChannel);
	}
	
	/**
	 * Puts a given event to an event queue.
	 * 
	 * @param pEvent A given event.
	 * @param pEventQueue An event queue.
	 * @throws InterruptedException
	 */
	public static void putEventToReaderQueue(Event pEvent, ArrayBlockingQueue<Event> pEventQueue) throws InterruptedException{
		putEventToQueue(pEvent, pEventQueue);
	}
	
	private static void putEventToQueue(Event pEvent, ArrayBlockingQueue<Event> pEventQueue) throws InterruptedException{
		if(EventParamsManager.isUseSimplifiedValuesEnabled()){
			if(asserEventProbability(pEvent)){
				pEventQueue.put(pEvent);
			} else {
				DesktopFrame.writeLogInfo(NameConsts.DISCARDINGAMESSAGE + pEvent);
			}
		} else {
			pEventQueue.put(pEvent);
		}
	}
	
	private static void dispatchEvent(ArrayList<Event> pEventList, EventChannel pEventChannel){
		for(Event event : pEventList){
			delayEvent(event);// delay
			
			if(!EventParamsManager.isUseSimplifiedValuesEnabled()){
				if(asserEventProbability(event)){
					pEventChannel.dispatchEvent(event);
				} else {
					DesktopFrame.writeLogInfo(NameConsts.DISCARDINGAMESSAGE + event);
				}
			} else {
				pEventChannel.dispatchEvent(event);
			}
		}
	}
	
	private static void delayEvent(Event pEvent){
		Long delay = EventParamsManager.getEventDelay(pEvent.getClass());
		try {
			Thread.sleep(delay);
		} catch (InterruptedException e) {
			DesktopFrame.writeLogError(NameConsts.UNABLETODELAYANEVENT + pEvent);
		}
	}
	
	private static Boolean asserEventProbability(Event pEvent){
		Boolean assertEvent = false;
		
		Double random = Math.random();
		Double eventProbability = EventParamsManager.getEventProbability(pEvent.getClass());
		
		if(random < eventProbability){
			assertEvent = true;
		}
		
		return assertEvent;
	}
	
	private static ArrayList<Event> createEventList(Event pEvent, Class<? extends Entity> pProducerClass){
		ArrayList<Event> eventList = new ArrayList<Event>();
		eventList.add(pEvent);
		
		if(!EventParamsManager.isUseSimplifiedValuesEnabled()){
			Boolean canPerformEffects = EventProducerManager.assertMainProducer(pEvent.getClass(), pProducerClass);
			
			if(canPerformEffects){
				if(EventParamsManager.isEventEffectsEnabledAndReadyToUse(pEvent.getClass())){
					if(EventParamsManager.isEventDuplicationEnabled(pEvent.getClass())){
						eventList.add(pEvent); //duplication
						DesktopFrame.writeLogInfo(NameConsts.DUPLICATINGANEVENT + pEvent);
					} else {
						eventList.remove(pEvent); //loss
						DesktopFrame.writeLogInfo(NameConsts.LOSINGANEVENT + pEvent);
					}
				}
			}
		}
		
		return eventList;
	}
}